package com.xyy.saas.payment.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.pingan.openbank.api.sdk.client.ApiClient;
import com.pingan.openbank.api.sdk.entity.SignRequest;
import com.xyy.saas.payment.callback.core.dto.CallbackMsg;
import com.xyy.saas.payment.callback.core.result.CallbackRunner;
import com.xyy.saas.payment.cores.enums.FinanceChannelEnum;
import com.xyy.saas.payment.cores.enums.PinganLoanApplyStatusEnum;
import com.xyy.saas.payment.cores.vo.*;
import com.xyy.saas.payment.dao.model.PayFinanceApply;
import com.xyy.saas.payment.service.PinganLoanFinanceApplyService;
import com.xyy.saas.payment.util.ApolloUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.DependsOn;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Map;

/**
 * 平安贷通知回调
 */
@RestController
@RequestMapping(value = {"/api/pingan/loan/notify"})
@Slf4j
@DependsOn("apolloUtil")
public class PinganLoanNotifyController {

    // 实例化平安API对象
    private static ApiClient apiClient = ApiClient.getInstance(ApolloUtil.getProperty("pingan.configPath"));

    @Resource
    private CallbackRunner callbackRunner;

    @Resource
    private PinganLoanFinanceApplyService pinganLoanFinanceApplyService;

    /**
     * 10.2 授信状态通知
     */
    @RequestMapping(value = {"/applyStatus"}, method = {RequestMethod.POST})
    public ResponseEntity<String> applyStatusNotify(@RequestBody String notifyApplyStatusVoText, @RequestHeader Map<String, String> headerMap) {
        log.info("PinganLoanNotifyController applyStatusNotify begin notifyApplyStatusVoText:{}", notifyApplyStatusVoText);
        PinganLoanNotifyApplyStatusVo notifyApplyStatusVo = JSONObject.parseObject(notifyApplyStatusVoText, PinganLoanNotifyApplyStatusVo.class);
        log.info("PinganLoanNotifyController applyStatusNotify begin PinganLoanNotifyApplyStatusVo:{}", JSON.toJSON(notifyApplyStatusVo));
        log.info("PinganLoanNotifyController applyStatusNotify begin request header map:{}", headerMap);

        if (!checkSign(notifyApplyStatusVoText, headerMap.get("x-pab-signature"))) {
            PinganLoanNotifyResultVo resultVo = PinganLoanNotifyResultVo.createError("签名校验失败");
            return convertToResponseEntityWithSign(resultVo);
        }

        // 校验以及落库 (支付中台订单编号是否存在 & 支付中台订单与银行回调时 客户编号是否一致)
        PayFinanceApply payFinanceApply = pinganLoanFinanceApplyService.selectByThirdApplyNo(notifyApplyStatusVo.getThirdApplyNo());
        if (payFinanceApply == null) {
            PinganLoanNotifyResultVo resultVo = PinganLoanNotifyResultVo.createError("外部申请编号在业务侧不存在");
            return convertToResponseEntityWithSign(resultVo);
        }

        if (!StringUtils.equals(notifyApplyStatusVo.getUserId(), payFinanceApply.getBusinessUserId())) {
            PinganLoanNotifyResultVo resultVo = PinganLoanNotifyResultVo.createError("客户编号不一致");
            return convertToResponseEntityWithSign(resultVo);
        }

        // 落库
        payFinanceApply.setBecifId(notifyApplyStatusVo.getBecifId());
        payFinanceApply.setContractNo(notifyApplyStatusVo.getContractNo());
        payFinanceApply.setApplyStatus(notifyApplyStatusVo.getApplyStatus().getCode());
        payFinanceApply.setAmountStartDate(notifyApplyStatusVo.getAmountStartdate());
        payFinanceApply.setAmountEndDate(notifyApplyStatusVo.getAmountEnddate());
        payFinanceApply.setApproveAmount(notifyApplyStatusVo.getApproveAmount()); // 授信额度(单位分) 单位：分，已签署合同成功时返回

        if (notifyApplyStatusVo.getApplyStatus().equals(PinganLoanApplyStatusEnum.SUBMIT_DENY) ||
                notifyApplyStatusVo.getApplyStatus().equals(PinganLoanApplyStatusEnum.APPROVE_DENY) ||
                notifyApplyStatusVo.getApplyStatus().equals(PinganLoanApplyStatusEnum.SIGN_FAILED) ||
                notifyApplyStatusVo.getApplyStatus().equals(PinganLoanApplyStatusEnum.INVALID)) {
            payFinanceApply.setDenyReason(notifyApplyStatusVo.getDenyReason());
        }

        pinganLoanFinanceApplyService.updateByPrimaryKeySelective(payFinanceApply);

        notifyApplyStatusVo.setCreditChannel(FinanceChannelEnum.PINGAN.getCode());

        // 回调EC
        CallbackMsg callbackMsg = new CallbackMsg();
        callbackMsg.setCallback("ec_pingan_credit");
        callbackMsg.setType("applyStatus");
        callbackMsg.setExtend(JSON.toJSONString(notifyApplyStatusVo));

        callbackRunner.callback(callbackMsg);

        log.info("PinganLoanNotifyController applyStatusNotify end");

        PinganLoanNotifyResultVo resultVo = PinganLoanNotifyResultVo.createSuccess();
        return convertToResponseEntityWithSign(resultVo);
    }

    /**
     * 10.3 融资提款状态通知
     */
    @RequestMapping(value = {"/withdraw"}, method = {RequestMethod.POST})
    public ResponseEntity<String> withdrawNotify(@RequestBody String notifyWithdrawVoText, @RequestHeader Map<String, String> headerMap) {
        log.info("PinganLoanNotifyController withdrawNotify begin notifyWithdrawVoText:{}", notifyWithdrawVoText);
        PinganLoanNotifyWithdrawVo notifyWithdrawVo = JSONObject.parseObject(notifyWithdrawVoText, PinganLoanNotifyWithdrawVo.class);
        log.info("PinganLoanNotifyController withdrawNotify begin PinganLoanNotifyWithdrawVo:{}", JSON.toJSON(notifyWithdrawVo));
        log.info("PinganLoanNotifyController applyStatusNotify begin request header map:{}", headerMap);

        if (!checkSign(notifyWithdrawVoText, headerMap.get("x-pab-signature"))) {
            PinganLoanNotifyResultVo resultVo = PinganLoanNotifyResultVo.createError("签名校验失败");
            return convertToResponseEntityWithSign(resultVo);
        }

        // 回调EC
        CallbackMsg callbackMsg = new CallbackMsg();
        callbackMsg.setCallback("ec_pingan_credit");
        callbackMsg.setType("withdraw");
        callbackMsg.setExtend(JSON.toJSONString(notifyWithdrawVo));

        callbackRunner.callback(callbackMsg);

        log.info("PinganLoanNotifyController withdrawNotify end");
        return convertToResponseEntityWithSign(PinganLoanNotifyResultVo.createSuccess());
    }

    /**
     * 10.4 融资提前还款接口通知接口
     */
    @RequestMapping(value = {"/repay"}, method = {RequestMethod.POST})
    public ResponseEntity<String> repayNotify(@RequestBody String notifyRepayVoText, @RequestHeader Map<String, String> headerMap) {
//        log.info("PinganLoanNotifyController repayNotify begin notifyRepayVoText:{}", notifyRepayVoText);
//        PinganLoanNotifyRepayVo notifyRepayVo = JSONObject.parseObject(notifyRepayVoText, PinganLoanNotifyRepayVo.class);
//        log.info("PinganLoanNotifyController repayNotify begin PinganLoanNotifyRepayVo:{}", JSON.toJSON(notifyRepayVo));
//        log.info("PinganLoanNotifyController applyStatusNotify begin request header map:{}", headerMap);
//
//        if (!checkSign(notifyRepayVoText, headerMap.get("x-pab-signature"))) {
//            PinganLoanNotifyResultVo resultVo = PinganLoanNotifyResultVo.createError("签名校验失败");
//            return convertToResponseEntityWithSign(resultVo);
//        }
//
//        PayFinanceApply payFinanceApply = pinganLoanFinanceApplyService.selectByLoanBalanceNo(notifyRepayVo.getLoanBalanceNo());
//        if (payFinanceApply == null) {
//            return convertToResponseEntityWithSign(PinganLoanNotifyResultVo.createError("借据号查询贷款申请不存在"));
//        }
//
//        // 回调EC
//        notifyRepayVo.setThirdApplyNo(payFinanceApply.getThirdApplyNo());
//        notifyRepayVo.setUserId(payFinanceApply.getBusinessUserId());
//
//        CallbackMsg callbackMsg = new CallbackMsg();
//        callbackMsg.setCallback("ec_pingan_credit");
//        callbackMsg.setType("repay");
//        callbackMsg.setExtend(JSON.toJSONString(notifyRepayVo));
//
//        callbackRunner.callback(callbackMsg);
//
//        log.info("PinganLoanNotifyController repayNotify end");
        return convertToResponseEntityWithSign(PinganLoanNotifyResultVo.createSuccess());
    }

    private boolean checkSign(String data, String sign) {
        if (StringUtils.isBlank(sign)) {
            log.info("PinganLoanNotifyController checkSign sign is blank");
            return false;
        }
        if (StringUtils.isBlank(data)) {
            log.info("PinganLoanNotifyController checkSign data is blank");
            return false;
        }
        SignRequest signRequest = new SignRequest();
        signRequest.setConfigFilePath(ApolloUtil.getProperty("pingan.configPath"));
        signRequest.setBizData(data);
        signRequest.setSign(sign);
        boolean checkResult = apiClient.outReqVerify(signRequest);
        log.info("PinganLoanNotifyController checkSign checkResult={}", checkResult);
        return checkResult;
    }

    private ResponseEntity<String> convertToResponseEntityWithSign(Object result) {
        SignRequest signRequest = new SignRequest();
        signRequest.setConfigFilePath(ApolloUtil.getProperty("pingan.configPath"));
        String bizData = JSON.toJSONString(result);
        signRequest.setBizData(bizData);
        String signData = apiClient.outRespSign(signRequest);
        log.info("PinganLoanNotifyController convertToResponseEntityWithSign bizData={}, signData={}", bizData, signData);

        return ResponseEntity.ok()
                .header("x-busi-signature", signData)
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .body(bizData);
    }

    public static class PinganLoanNotifyResultVo {

        @JSONField(name = "ResponseCode")
        private String ResponseCode;
        @JSONField(name = "ResponseMessage")
        private String ResponseMessage;

        public static PinganLoanNotifyResultVo createSuccess()  {
            PinganLoanNotifyResultVo resultVo = new PinganLoanNotifyResultVo();
            resultVo.setResponseCode("000000");
            resultVo.setResponseMessage("success");
            return resultVo;
        }

        public static PinganLoanNotifyResultVo createError(String msg)  {
            PinganLoanNotifyResultVo resultVo = new PinganLoanNotifyResultVo();
            resultVo.setResponseCode("-1");
            resultVo.setResponseMessage(msg);
            return resultVo;
        }

        public String getResponseCode() {
            return ResponseCode;
        }

        public void setResponseCode(String responseCode) {
            ResponseCode = responseCode;
        }

        public String getResponseMessage() {
            return ResponseMessage;
        }

        public void setResponseMessage(String responseMessage) {
            ResponseMessage = responseMessage;
        }
    }

}
